#pragma once 

#include "String.h"

class vlong // very long integer - can be used like long
{
private:
  class vlong_value * value;
  int negative;
  int cf( const vlong x ) const;
  void docopy();
  friend class monty;
public:
  // Standard arithmetic operators
  friend vlong operator +( const vlong& x, const vlong& y );
  friend vlong operator -( const vlong& x, const vlong& y );
  
  friend vlong operator +( const vlong& x, const int& y );
  friend vlong operator -( const vlong& x, const int& y );

  friend vlong operator *( const vlong& x, const vlong& y );
  friend vlong operator /( const vlong& x, const vlong& y );
  friend vlong operator %( const vlong& x, const vlong& y );

  friend vlong operator *( const vlong& x, const int& y );
  friend vlong operator /( const vlong& x, const int& y );
  friend vlong operator %( const vlong& x, const int& y );
  
  vlong& operator +=( const vlong& x );
  vlong& operator -=( const vlong& x );

  vlong& operator +=( const int& x );
  vlong& operator -=( const int& x );

  // Standard comparison operators
  friend inline int operator !=( const vlong& x, const vlong& y ){ return x.cf( y ) != 0; }
  friend inline int operator ==( const vlong& x, const vlong& y ){ return x.cf( y ) == 0; }
  friend inline int operator >=( const vlong& x, const vlong& y ){ return x.cf( y ) >= 0; }
  friend inline int operator <=( const vlong& x, const vlong& y ){ return x.cf( y ) <= 0; }
  friend inline int operator > ( const vlong& x, const vlong& y ){ return x.cf( y ) > 0; }
  friend inline int operator < ( const vlong& x, const vlong& y ){ return x.cf( y ) < 0; }

  friend inline int operator !=( const vlong& x, const int& y ){ return x.cf( (vlong)y ) != 0; }
  friend inline int operator ==( const vlong& x, const int& y ){ return x.cf( (vlong)y ) == 0; }
  friend inline int operator >=( const vlong& x, const int& y ){ return x.cf( (vlong)y ) >= 0; }
  friend inline int operator <=( const vlong& x, const int& y ){ return x.cf( (vlong)y ) <= 0; }
  friend inline int operator > ( const vlong& x, const int& y ){ return x.cf( (vlong)y ) > 0; }
  friend inline int operator < ( const vlong& x, const int& y ){ return x.cf( (vlong)y ) < 0; }

  // Construction and conversion operations
  vlong ( unsigned x=0 );
  vlong ( const vlong& x );
  ~vlong();
  operator unsigned ();
  vlong& operator =(const vlong& x);

  vlong& operator =(const int& x);
  unsigned Get(unsigned x);
  unsigned Len();

};

vlong modexp( const vlong & x, const vlong & e, const vlong & m ); // m must be odd
vlong gcd( const vlong &X, const vlong &Y ); // greatest common denominator
vlong modinv( const vlong &a, const vlong &m ); // modular inverse

vlong from_str( const char * s ,int len = -1);
vlong from_decstr( const char * s );
vlong from_hexstr( const char * s );

AStr to_hexstr( const vlong vl);
AStr to_decstr( const vlong vl);

